﻿using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Linq;
using System.Text;

using FRL.DebtChased.Extensions;
using FRL.DebtChased.Types;

namespace FRL.DebtChased.Repository.ViewModels
{

	/// <summary>
	/// Declaration of DocumentModel class
	/// </summary>
	[Serializable]
	public class DocumentModel
	{

		/////////////////////////////////////////////////////////////
		// Nested classes

		[Serializable]
		public class Element
		{

			/////////////////////////////////////////////////////////
			// Attributes

			internal int m_iDocumentId;
			public int DocumentId
			{
				get { return m_iDocumentId; }
			}

			internal string m_strFileName;

			internal string m_strDownloadUrl;
			public string DownloadUrl
			{
				get { return m_strDownloadUrl; }
			}

			internal string m_strDocumentName;
			public string DocumentName
			{
				get { return m_strDocumentName; }
				set { m_strDocumentName = value; }
			}

			internal bool m_bInUse;
			public bool InUse
			{
				get { return m_bInUse; }
			}
			public string InUseAsText
			{
				get { return m_bInUse ? "YES" : "NO"; }
			}

			internal int m_iBytes;
			public string BytesAsText
			{
				get { return FRL.DebtChased.Extensions.Extensions.FriendlyFilesize(m_iBytes); }
			}

			internal DateTime m_dtModifiedAt;
			internal string m_strModifiedBy;

			public string AtAndByText
			{
				get { return string.Format( "{0} by {1}", m_dtModifiedAt.ToCuteString(), m_strModifiedBy ); }
			}

			internal AccountInvoiceModel m_AccountInvoices = new AccountInvoiceModel();
			public AccountInvoiceModel AccountInvoices
			{
				get { return m_AccountInvoices; }
			}

			/////////////////////////////////////////////////////////
			// Construction

			public Element()
			{
			}

			public Element(DebtChasedEntities ent, int iDocumentId)
			{

				// Load document details
				var result = ent.DocumentsProc(null, iDocumentId).FirstOrDefault();
				_set( ent, result );

			}

			public Element(DebtChasedEntities ent, DocumentsProc_Row row )
			{

				// Load document details
				_set( ent, row );

			}

			/////////////////////////////////////////////////////////
			// Operations

			internal void _set( DebtChasedEntities ent, DocumentsProc_Row row )
			{
#if DEBUG
				Debug.Assert(row != null);
#endif // #if DEBUG

				// Set member variables
				this.m_iDocumentId = row.fdDocumentId;
				this.m_strFileName = row.fdFileName;
				this.m_strDocumentName = row.fdDocumentName;
				this.m_iBytes = row.fdBytes;
				this.m_bInUse = false;

				// Get the invoices
				var invoices = from ai in ent.AccountInvoices
							   join dai in ent.DocumentAccountInvoices on ai.AccountInvoiceId equals dai.AccountInvoiceId
							   join a in ent.Accounts on ai.AccountId equals a.AccountId
							   where dai.DocumentId == m_iDocumentId
							   select new { ai.AccountInvoiceId, a.FRLReference, a.ClientReference, ai.InvoiceNo, ai.AmountCurrency, ai.AmountValue };
				foreach (var invoice in invoices)
				{

					// Update flag
					this.m_bInUse = true;

					// Get the current code
					Money.eCurrency currency = Money.ParseCurrencyCode(invoice.AmountCurrency);

					// Add an element
					this.AccountInvoices.Elements.Add(new AccountInvoiceModel.Element()
					{
						AccountInvoiceId = invoice.AccountInvoiceId,
						InvoiceNo = invoice.InvoiceNo,
						FRLRef = invoice.FRLReference,
						ClientRef = invoice.ClientReference,
						Amount = new Types.Money(invoice.AmountValue, currency)
					});

				}

			}

		}

		/////////////////////////////////////////////////////////////
		// Attributes

		private List<Element> m_elements = new List<Element>();
		public List<Element> Elements
		{
			get { return m_elements; }
		}

		/////////////////////////////////////////////////////////////
		// Construction

		public DocumentModel( DebtChasedEntities ent, int? iClientId, string strDocumentFolderUrl )
		{

			// Load stored procedure
			var results = ent.DocumentsProc(iClientId,null);
			foreach (var result in results)
			{

				// Add a new element
				Element el = new Element(ent,result);
				m_elements.Add(el);

				// Compose the download url
				el.m_strDownloadUrl = Document.ComposeDownloadUrl(strDocumentFolderUrl, el.m_strFileName);

			}

		}

		/////////////////////////////////////////////////////////////
		// Static Operations

		public static string Set(DebtChasedEntities ent, Element el, int iUserId)
		{
#if DEBUG
			Debug.Assert(el.DocumentId > 0);
#endif // #if DEBUG

			// Declare return variable
			string strFtmp = null;

			try
			{
				
				// Load document
				Document doc = (from d in ent.Documents.Include("DocumentAccountInvoices")
							   where d.DocumentId == el.DocumentId
							   select d).FirstOrDefault();
				if (doc != null)
				{

					// Track user actions
					UserAction.Session session = new UserAction.Session(iUserId, doc, el.DocumentName);

					// Update fields
					doc.DocumentName = el.DocumentName;

					// Update attached invoices
					List<DocumentAccountInvoice> attachedInvoices = doc.DocumentAccountInvoices.ToList();
					foreach(DocumentAccountInvoice dai in attachedInvoices)
					{

						// Find in element
						bool bFound = false;
						foreach(AccountInvoiceModel.Element loop in el.AccountInvoices.Elements)
						{
							if(loop.AccountInvoiceId == dai.AccountInvoiceId)
							{
								bFound = true;
								break;
							}
						}

						// If not found...
						if(!bFound)
						{

							// Delete this attachment
							ent.DocumentAccountInvoices.DeleteObject(dai);

						}

					}

					// Add new attached invoices
					foreach(AccountInvoiceModel.Element loop in el.AccountInvoices.Elements)
					{

						// Find in current
						bool bFound = false;
						foreach(DocumentAccountInvoice dai in attachedInvoices)
						{
							if(dai.AccountInvoiceId == loop.AccountInvoiceId)
							{
								bFound = true;
								break;
							}
						}

						// If not found...
						if(!bFound)
						{

							// Add a new attachment
							DocumentAccountInvoice newDai = DocumentAccountInvoice.CreateDocumentAccountInvoice(0,el.DocumentId,loop.AccountInvoiceId);
							ent.DocumentAccountInvoices.AddObject(newDai);

						}

					}

					// Save changes
					ent.SaveChanges();

					// Save user actions
					session.SaveChanges(ent);

				}

			}
			catch (Exception x)
			{

				// Update error
				strFtmp = ErrorProcessing.HandleException(x, "updating document", iUserId);

			}

			// Return variable
			return strFtmp;

		}

	}

}
